﻿using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using DTBuilderLib;
using IndicoInterface;
using IndicoInterface.SimpleAgendaDataModel;
using System.IO;

namespace t_DTBuilderLib
{
    /// <summary>
    /// Tests the meeting downloader.
    /// WARNING: The downloader caches -- so if you have already done the download this will be very quick and
    /// may not really exercise the code!!!
    /// </summary>
    [TestClass]
    public class t_JobDownloader
    {
        public t_JobDownloader()
        {
            //
            // TODO: Add constructor logic here
            //
        }

        private TestContext testContextInstance;

        /// <summary>
        ///Gets or sets the test context which provides
        ///information about and functionality for the current test run.
        ///</summary>
        public TestContext TestContext
        {
            get
            {
                return testContextInstance;
            }
            set
            {
                testContextInstance = value;
            }
        }

        #region Additional test attributes
        //
        // You can use the following additional attributes as you write your tests:
        //
        // Use ClassInitialize to run code before running the first test in the class
        // [ClassInitialize()]
        // public static void MyClassInitialize(TestContext testContext) { }
        //
        // Use ClassCleanup to run code after all tests in a class have run
        // [ClassCleanup()]
        // public static void MyClassCleanup() { }
        //
        // Use TestInitialize to run code before running each test 
        // [TestInitialize()]
        // public void MyTestInitialize() { }
        //
        // Use TestCleanup to run code after each test has run
        // [TestCleanup()]
        // public void MyTestCleanup() { }
        //
        #endregion

        [TestMethod]
        public void JobDownloaderCtor()
        {
            JobDownloader jd = new JobDownloader();
            Assert.IsTrue(jd.TicksBetweenProgressUpdates == 1000, "Wrong timeing for update calls");

            jd.TicksBetweenProgressUpdates = 250;

            Assert.IsTrue(jd.TicksBetweenProgressUpdates == 250, "Wrong timing reset for update calls");
        }

#if false
        /// This is a protected meeting now.
        [TestMethod]
        public void JobDownloaderSingleJob()
        {
            /// Download a simple agenda (I hope this is fast!!).
            /// This test depends on undocumented behavior. If the files are already downloaded, then we don't expect
            /// any status updates - and that is how we tell we don't need to think about status updates.

            AgendaInfo a = new AgendaInfo(33078);

            Meeting finalMeeting = null;
            bool seencallback = false;
            float maxpercent = 0;
            Dictionary<Talk, int> filedone = new Dictionary<Talk, int>();

            bool statusUpdatesOccured = false;

            JobDownloader jd = new JobDownloader() { TicksBetweenProgressUpdates = 200 };
            jd.StartMeetingDownload(a.GetNormalizedConferenceData(),
                (m, s, t, p) =>
                {
                    if (p == 100.0F)
                    {
                        filedone[t] = 1;
                    }
                    else
                    {
                        statusUpdatesOccured = true;
                        if (p > maxpercent)
                        {
                            maxpercent = p;
                        }
                    }
                    lock (this)
                    {
                        seencallback = true;
                    }
                },
                (m) => { finalMeeting = m; });

            /// Now, wait until this is done.
            while (finalMeeting == null)
            {
                System.Threading.Thread.Sleep(500);
                lock (this)
                {
                    if (!seencallback)
                    {
                        Assert.Fail("No progress callbacks in time!");
                        break;
                    }
                    seencallback = false;
                }
            }

            /// Did we get some percentages??
            Assert.IsTrue(!statusUpdatesOccured || maxpercent > 1.0, "Max percent was never above 1.0");

            /// Check to see if we are done.
            Assert.IsTrue(filedone.Keys.Count == 4, "Number of files downloaded was not 4");

            /// Check to see that all files actually exist on disk.
            Assert.IsTrue(AllFilesExist(finalMeeting), "Not all files were correctly downloaded!");

            //Assert.Fail("Test is not looking at callback frequency right now");
        }
#endif

        /// <summary>
        /// Helper guy that makes sure all files exist in the meeting.
        /// </summary>
        /// <param name="finalMeeting"></param>
        /// <returns></returns>
        private bool AllFilesExist(Meeting finalMeeting)
        {
            var badfile = from s in finalMeeting.Sessions
                          from t in s.Talks
                          where t.SlideURL != null
                          where t.SlideURL.Length > 0
                          where !File.Exists(t.SlideURL)
                          select t.SlideURL;

            var alldudes = badfile.ToArray();
            /// Next line isn't most efficient, but hey...

            return badfile.Count() == 0;
        }

#if false
        /// Meeting is now protected.
        [TestMethod]
        public void SimpleDownloadInterface()
        {
            AgendaInfo a = new AgendaInfo(33078);
            JobDownloader jd = new JobDownloader();
            var data = jd.DownloadMeeting (a.GetNormalizedConferenceData());

            /// Check to see that all files actually exist on disk.
            Assert.IsTrue(AllFilesExist(data), "Not all files were correctly downloaded!");
        }
        [TestMethod]
        public void BigMeetingDownload()
        {
            AgendaInfo a = new AgendaInfo(14475);
            JobDownloader jd = new JobDownloader();
            var data = jd.DownloadMeeting(a.GetNormalizedConferenceData());

            /// Check to see that all files actually exist on disk.
            Assert.IsTrue(AllFilesExist(data), "Not all files were correctly downloaded!");
        }
#endif


        [TestMethod]
        public void DownloadPPT()
        {
            /// PPT version
            Talk t1 = new Talk() { Title = "talk-ppt", ID = "5", StartDate = DateTime.Now, EndDate = DateTime.Now, SlideURL = "http://indico.fnal.gov/getFile.py/access?contribId=6&sessionId=1&resId=2&materialId=slides&confId=1829" };
            /// PDF version
            Talk t2 = new Talk() { Title = "talk-pdf", ID = "6", StartDate = DateTime.Now, EndDate = DateTime.Now, SlideURL = "http://indico.fnal.gov/getFile.py/access?contribId=6&sessionId=1&resId=1&materialId=slides&confId=1829" };
            Session s = new Session() { Title = "session1", ID = "2", StartDate = DateTime.Now, EndDate = DateTime.Now };
            s.Talks = new Talk[] { t1, t2 };
            Meeting m = new Meeting() { Title = "Meeting", StartDate = DateTime.Now, EndDate = DateTime.Now, ID = "2" };
            m.Sessions = new Session[] { s };

            JobDownloader jd = new JobDownloader();
            jd.FileDownloadLocation = Environment.CurrentDirectory;

            Meeting mdown = jd.DownloadMeeting(m);
            Assert.IsTrue(AllFilesExist(mdown), "Not all files were downloaded!");
            Console.WriteLine(mdown.Sessions[0].Talks[0].SlideURL);
            Console.WriteLine(mdown.Sessions[0].Talks[1].SlideURL);
            Assert.IsTrue(mdown.Sessions[0].Talks[1].SlideURL.EndsWith(".pdf"), "PDF file does not end with pdf file type");
            Assert.IsTrue(mdown.Sessions[0].Talks[0].SlideURL.EndsWith(".ppt"), "PPT file does not end with ppt file type");
        }

        [TestMethod]
        public void DownloadPS()
        {
            /// There is a PS version of a talk out there. Make sure it downloads correctly

            Talk t1 = new Talk() { Title = "talk-ppt", ID = "7", StartDate = DateTime.Now, EndDate = DateTime.Now, SlideURL = "http://indico.cern.ch/getFile.py/access?contribId=s1t14&resId=0&materialId=0&confId=a042880" };
            Session s = new Session() { Title = "session1", ID = "2", StartDate = DateTime.Now, EndDate = DateTime.Now };
            s.Talks = new Talk[] { t1 };
            Meeting m = new Meeting() { Title = "Meeting", StartDate = DateTime.Now, EndDate = DateTime.Now, ID = "2" };
            m.Sessions = new Session[] { s };

            JobDownloader jd = new JobDownloader();
            jd.FileDownloadLocation = Environment.CurrentDirectory;

            Meeting mdown = jd.DownloadMeeting(m);
            Assert.IsTrue(AllFilesExist(mdown), "Not all files were downloaded!");
            Assert.IsNotNull(mdown.Sessions[0].Talks[0].SlideURL, "Slide URL should not be null after a download attempt!");
            Console.WriteLine(mdown.Sessions[0].Talks[0].SlideURL);
            Assert.IsTrue(mdown.Sessions[0].Talks[0].SlideURL.EndsWith(".ps"), "PS file does not end with ps file type");

        }

        [TestMethod]
        public void DownloadPPTX()
        {
            /// there is a PPTX version of a talk out there - make sure it downloads correctly.

            Talk t1 = new Talk() { Title = "talk-pptx", ID = "8", StartDate = DateTime.Now, EndDate = DateTime.Now, SlideURL = "http://indico.cern.ch/getFile.py/access?contribId=500&sessionId=28&resId=0&materialId=poster&confId=35523" };
            Session s = new Session() { Title = "session1", ID = "2", StartDate = DateTime.Now, EndDate = DateTime.Now };
            s.Talks = new Talk[] { t1 };
            Meeting m = new Meeting() { Title = "Meeting", StartDate = DateTime.Now, EndDate = DateTime.Now, ID = "2" };
            m.Sessions = new Session[] { s };

            JobDownloader jd = new JobDownloader();
            jd.FileDownloadLocation = Environment.CurrentDirectory;

            Meeting mdown = jd.DownloadMeeting(m);
            Assert.IsTrue(AllFilesExist(mdown), "Not all files were downloaded!");
            Assert.IsNotNull(mdown.Sessions[0].Talks[0].SlideURL, "Slide URL should not be null after a download attempt!");
            Console.WriteLine(mdown.Sessions[0].Talks[0].SlideURL);
            Assert.IsTrue(mdown.Sessions[0].Talks[0].SlideURL.EndsWith(".pptx"), "pptx file does not end with pptx file type");
        }

        [TestMethod]
        public void DownloadFTP()
        {
            ///
            /// Sometimes people store talks in ftp links (yeah, I know, I know).
            /// 

            Talk t1 = new Talk() { Title = "talk-pptx", ID = "8", StartDate = DateTime.Now, EndDate = DateTime.Now, SlideURL = "ftp://fess-ftp.fnal.gov/public/ILC/TILC09%20CFS%20Agenda.pdf" };
            Session s = new Session() { Title = "session1", ID = "2", StartDate = DateTime.Now, EndDate = DateTime.Now };
            s.Talks = new Talk[] { t1 };
            Meeting m = new Meeting() { Title = "Meeting", StartDate = DateTime.Now, EndDate = DateTime.Now, ID = "2" };
            m.Sessions = new Session[] { s };

            JobDownloader jd = new JobDownloader();
            jd.FileDownloadLocation = Environment.CurrentDirectory;

            Meeting mdown = jd.DownloadMeeting(m);
            Assert.IsNull(mdown.Sessions[0].Talks[0].SlideURL, "Slide URL should be null after a download attempt of bad URL!");
        }

        [TestMethod]
        public void DownloadBadPPTX()
        {
            ///
            /// See how things work when a URL is bad and points to nothing.
            /// 

            Talk t1 = new Talk() { Title = "talk-pptx", ID = "8", StartDate = DateTime.Now, EndDate = DateTime.Now, SlideURL = "http://indico.cern.ch/getFile.py/access?contribId=50000000&sessionId=28&resId=0&materialId=poster&confId=35523" };
            Session s = new Session() { Title = "session1", ID = "2", StartDate = DateTime.Now, EndDate = DateTime.Now };
            s.Talks = new Talk[] { t1 };
            Meeting m = new Meeting() { Title = "Meeting", StartDate = DateTime.Now, EndDate = DateTime.Now, ID = "2" };
            m.Sessions = new Session[] { s };

            JobDownloader jd = new JobDownloader();
            jd.FileDownloadLocation = Environment.CurrentDirectory;

            Meeting mdown = jd.DownloadMeeting(m);
            Assert.IsNull(mdown.Sessions[0].Talks[0].SlideURL, "Slide URL should be null after a download attempt of bad URL!");
        }
    }
}
